package com.fulu.game.bi.common.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.fulu.game.bi.common.exception.UploadException;
import com.fulu.game.bi.common.util.lang.GenIdUtil;
import com.fulu.game.bi.common.util.lang.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
public class OssUtil implements InitializingBean {

    @Value("${config.oss.endpoint}")
    private String endpoint;

    @Value("${config.oss.bucketName}")
    private String bucketName;

    @Value("${config.oss.host}")
    private String host;

    @Value("${config.oss.accessKeyId}")
    private String accessKeyId;

    @Value("${config.oss.accessKeySecret}")
    private String accessKeySecret;

    public static final String TEMP = "temp/";
    public static final String EXPORT = TEMP + "export/";
    public static final String CACHE_CONTROL = "only-if-cached";

    public static OSSClient ossClient;

    public String getHost() {
        return host;
    }

    public String getBucketName() {
        return bucketName;
    }

    /**
     * 上传文件
     *
     * @param inputStream
     * @param fileName
     * @return
     */
    public String uploadFile(InputStream inputStream, String fileName) {
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            String key = generateTempOssKey(fileName);
            ObjectMetadata meta = new ObjectMetadata();
            // 设置浏览器缓存属性 :  表明客户端只接受已缓存的响应，并且不要向原始服务器检查是否有更新的拷贝.
            meta.setCacheControl(CACHE_CONTROL);
            PutObjectRequest request = new PutObjectRequest(bucketName, key, inputStream, meta);
            ossClient.putObject(request);
            boolean exists = ossClient.doesObjectExist(bucketName, key);
            if (exists) {
                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
                return host + key;
            }
        } finally {
            ossClient.shutdown();
        }
        return null;
    }

    /**
     * 上传文件(自定义文件名称)
     *
     * @param inputStream
     * @param fileName
     * @return
     */
    public String uploadFileCustom(InputStream inputStream, String fileName) {
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            String key = generateCustomTempOssKey(fileName);
            ObjectMetadata meta = new ObjectMetadata();
            // 设置浏览器缓存属性 :  表明客户端只接受已缓存的响应，并且不要向原始服务器检查是否有更新的拷贝.
            meta.setCacheControl(CACHE_CONTROL);
            PutObjectRequest request = new PutObjectRequest(bucketName, key, inputStream, meta);
            ossClient.putObject(request);
            boolean exists = ossClient.doesObjectExist(bucketName, key);
            if (exists) {
                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
                return host + key;
            }
        } finally {
            ossClient.shutdown();
        }
        return null;
    }


    /**
     * 判断文件是否在oss中存在
     *
     * @param fileUrl
     * @return
     */
    public Boolean ossFileIsExists(String fileUrl) {
        if (StringUtils.isEmpty(fileUrl)) {
            return false;
        }
        String sourceKey = formatOssKey(fileUrl);
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            return ossClient.doesObjectExist(bucketName, sourceKey);
        } finally {
            ossClient.shutdown();
        }
    }


    /**
     * 激活oss文件,删除临时上传的文件
     *
     * @param fileUrl
     * @return
     */
    public String activateOssFile(String fileUrl) {
        if (StringUtils.isEmpty(fileUrl)) {
            log.error("oss激活文件名为空");
            return null;
        }
        String sourceKey = formatOssKey(fileUrl);
        if (!sourceKey.contains("temp")) {
            return fileUrl;
        }
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            boolean sourceFileExists = ossClient.doesObjectExist(bucketName, sourceKey);
            String destinationKey = sourceKey.replace(TEMP, "");
            if (!sourceFileExists) {
                return host + destinationKey;
            }
            ossClient.copyObject(bucketName, sourceKey, bucketName, destinationKey);
            boolean exists = ossClient.doesObjectExist(bucketName, destinationKey);
            if (exists) {
                DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(CollectionUtil.newArrayList(sourceKey)));
                log.info("oss删除文件:{}", deleteObjectsResult.getDeletedObjects());
                ossClient.setObjectAcl(bucketName, destinationKey, CannedAccessControlList.PublicRead);
                return host + destinationKey;
            }
        } finally {
            ossClient.shutdown();
        }
        return null;
    }


    /**
     * C
     * 删除oss文件
     *
     * @param fileUrl
     */
    public void deleteFile(String... fileUrl) {
        if (fileUrl == null || fileUrl.length == 0) {
            return;
        }
        List<String> deleteUrls = new ArrayList<>();
        // 过滤掉非临时文件
        for (String url : fileUrl) {
            if (url != null && url.contains("temp/")) {
                deleteUrls.add(url);
            }
        }

        if (CollectionUtils.isEmpty(deleteUrls)) {
            return;
        }

        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {

            String[] myListArray = deleteUrls.toArray(new String[0]);

            DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(formatOssKey(myListArray)));
            log.info("oss删除文件:{}", deleteObjectsResult.getDeletedObjects());
        } catch (Exception e) {
            log.error("oss删除异常", e);
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 文件url路径格式化成ossKey
     *
     * @param fileUrl
     * @return
     */
    private String formatOssKey(String fileUrl) {
        URL url = null;
        try {
            url = new URL(fileUrl);
        } catch (Exception e) {
            log.error(String.format("执行OssUtil.formatOssKey()方法异常,fileUrl:%s", fileUrl), e);
            throw new UploadException(UploadException.ExceptionCode.URL_PATH_ERROR);//NOPMD
        }
        return url.getPath().substring(1);
    }


    /**
     * 文件url路径格式化成ossKey
     *
     * @param fileUrl
     * @return
     */
    private List<String> formatOssKey(String... fileUrl) {
        List<String> result = new ArrayList<>();
        for (String path : fileUrl) {
            try {
                URL url = new URL(path);
                String key = url.getPath().substring(1);
                result.add(key);
            } catch (Exception e) {
                log.error("文件路径格式化异常:", e);
            }
        }
        return result;
    }


    /**
     * 创建临时的temp
     *
     * @param fileName
     * @return
     */
    public static String generateTempOssKey(String fileName) {
        StringBuilder sb = new StringBuilder();
        String uuid = GenIdUtil.GetGUID();
        String ext = FileUtil.extName(fileName);
        sb.append(TEMP)
                .append(DateUtil.thisYear())
                .append("/").append(DateUtil.thisMonth() + 1)
                .append("/").append(DateUtil.thisDayOfMonth())
                .append("/").append(uuid).append(".").append(ext);
        return sb.toString();
    }

    public static void main(String[] args) {
        System.out.println(generateCustomTempOssKey("资金报表.xlsx"));
    }

    /**
     * 创建临时的temp
     *
     * @param fileName
     * @return
     */
    public static String generateCustomTempOssKey(String fileName) {
        StringBuilder sb = new StringBuilder();
        String uuid = GenIdUtil.GetImgNo();
        sb.append(TEMP)
                .append(DateUtil.thisYear())
                .append("/").append(DateUtil.thisMonth() + 1)
                .append("/").append(DateUtil.thisDayOfMonth())
                .append("/").append(uuid).append("/").append(fileName);
        return sb.toString();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
    }
}
